package com.basketball.gym.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.basketball.gym.mapper.*;
import com.basketball.gym.pojo.*;
import com.basketball.gym.pojo.Calendar;
import com.basketball.gym.pojo.state.RedisHeader;
import com.basketball.gym.pojo.state.ResponseState;
import com.basketball.gym.service.OrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.basketball.gym.utils.DateUtils;
import com.basketball.gym.utils.StringUtils;
import com.basketball.gym.utils.WXService;
import com.basketball.gym.utils.WrapperUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.text.ParseException;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 赵肖云
 * @since 2021-03-27
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Orders> implements OrderService {
    @Autowired
    private PriceMapper priceMapper;
    @Autowired
    private CalendarMapper calendarMapper;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private WXService wxService;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private WalletMapper walletMapper;
    @Autowired
    private FinanceMapper financeMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 计算价格
     */
    @Override
    public ResponseData<Orders> calculatePrice(Orders order) {
        Price unitPrice = priceMapper.selectOne(WrapperUtils.getOneEqQueryWrapper("id", order.getType()));
        if (order.getType() == 1) {
            order.setPrice(unitPrice.getPrice() * order.getTicketSum());
        } else if (order.getType() == 2 || order.getType() == 3) {
            JSONArray jsonArray = JSONArray.parseArray(order.getCalendarId());
            Object[] calendarIdArray = jsonArray.toArray();
            Set<Integer> calendarIdSet = new HashSet<>();
            for (Object calendarId : calendarIdArray) {
                calendarIdSet.add((Integer) calendarId);
            }
            if (calendarIdArray.length != calendarIdSet.size()) {
                return new ResponseData<>("calendarId有重复数据", ResponseState.PARAM_IS_ERROR.getValue());
            }
            order.setPrice(calendarIdSet.size() * unitPrice.getPrice());
        }
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue(), order);
    }

    /**
     * 发起订单
     */
    @Override
    @Transactional
    public ResponseData<Orders> postOrder(Orders order, User user) {
        System.out.println("发起订单");
        System.out.println(order
        );
        //计算价格
        Price unitPrice = priceMapper.selectOne(WrapperUtils.getOneEqQueryWrapper("id", order.getType()));
        List<Calendar> calendarListTypeTwo = new ArrayList<>();
        List<Calendar> calendarListTypeThree = new ArrayList<>();
        Set<Integer> calendarIdSet = null;
        if (order.getType() == 1) {
            System.out.println(unitPrice);
            order.setPrice(unitPrice.getPrice() * order.getTicketSum());
            System.out.println(order.getPrice());
        } else if (order.getType() == 2 || order.getType() == 3) {
            JSONArray jsonArray = JSONArray.parseArray(order.getCalendarId());
            Object[] calendarIdArray = jsonArray.toArray();
            calendarIdSet = new HashSet<>();
            for (Object calendarId : calendarIdArray) {
                calendarIdSet.add((Integer) calendarId);
                if (order.getType() == 2) {
                    //查询日程是否空闲
                    QueryWrapper<Calendar> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("date", order.getDate());
                    queryWrapper.eq("time_id", calendarId);
                    queryWrapper.eq("court_id", order.getCourtId());
                    Calendar calendar = calendarMapper.selectOne(queryWrapper);
                    if (calendar.getState() != 1) {
                        return new ResponseData<>(ResponseState.COURT_HAI_ORDER.getMessage(), ResponseState.COURT_HAI_ORDER.getValue());
                    }
                    calendarListTypeTwo.add(calendar);
                } else {
                    Calendar calendar = null;
                    if (order.getCourtId() == 5) {
                        calendar = calendarMapper.selectOneAllPresent(new Calendar((Integer) calendarId, order.getDate(), 1));
                    } else if (order.getCourtId() == 6) {
                        calendar = calendarMapper.selectOneAllPresent(new Calendar((Integer) calendarId, order.getDate(), 3));
                    } else {
                        return new ResponseData<>("courtId错误", ResponseState.PARAM_IS_ERROR.getValue());
                    }
                    if (calendar.getAState() != 1 || calendar.getBState() != 1) {
                        return new ResponseData<>(ResponseState.COURT_HAI_ORDER.getMessage(), ResponseState.COURT_HAI_ORDER.getValue());
                    }
                    calendarListTypeThree.add(calendar);

                }
            }
            if (calendarIdArray.length != calendarIdSet.size()) {
                return new ResponseData<>("calendarId有重复数据", ResponseState.PARAM_IS_ERROR.getValue());
            }
            order.setPrice(calendarIdSet.size() * unitPrice.getPrice());
        }
        order.setState(1);
        order.setUserId(user.getId());
        orderMapper.insert(order);
        //修改日程状态
        if (order.getType() == 2) {
            for (Calendar calendar : calendarListTypeTwo) {
                calendar.setState((short) 2);
                calendar.setUserId(user.getId());
                calendarMapper.updateById(calendar);
            }
        } else if (order.getType() == 3) {
            for (Calendar calendar : calendarListTypeThree) {
                calendar.setState((short) 2);
                calendar.setUserId(user.getId());
                calendarMapper.updateById(calendar);
                UpdateWrapper<Calendar> updateWrapper = new UpdateWrapper<>();
                updateWrapper.eq("date", order.getDate());
                updateWrapper.eq("time_id", calendar.getTimeId());
                updateWrapper.eq("court_id", calendar.getCourtId() + 1);
                calendarMapper.update(new Calendar(calendar.getTimeId(), order.getDate(), calendar.getCourtId() + 1, (short) 2,user.getId()), updateWrapper);
            }
        }
        stringRedisTemplate.opsForValue().set(RedisHeader.ORDER.getHeader() + order.getId(), String.valueOf(new Date().getTime()), 30, TimeUnit.MINUTES);
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue(), order);
    }

    /**
     * 充值
     */
    @Override
    public ResponseData<Object> topUp(Orders order, User user) throws ParseException {
        long timestamp = System.currentTimeMillis();
        String number = String.valueOf(timestamp) + user.getId();
        order.setOutTradeNo(number);
        order.setUserId(user.getId());
        order.setType(4);
        order.setDate(DateUtils.getTodayDate());
        order.setState(1);
        user = userMapper.selectById(user.getId());
        Map<String, Object> data = wxService.JSAPIPay("topUp", order.getOutTradeNo(), (int) (order.getPrice() * 100), user.getOpenId());
        if (data == null) {
            return new ResponseData<>(ResponseState.ERROR.getMessage(), ResponseState.ERROR.getValue());
        }
        orderMapper.insert(order);
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue(), data);
    }

    /**
     * 支付结果回调
     */
    @Override
    public void payResult(Map<String, Object> param) {
        System.out.println("充值回调");
        Map<String, Object> resource = (Map<String, Object>) param.get("resource");
        System.out.println(resource);
        try {
            Map<String, Object> result = wxService.decrypt(((String) resource.get("associated_data")).getBytes("UTF-8"), ((String) resource.get("nonce")).getBytes("UTF-8"), (String) resource.get("ciphertext"));
            String outTradeNo = (String) result.get("out_trade_no");
            String transactionId = (String) result.get("transaction_id");
            Orders order = orderMapper.selectOne(WrapperUtils.getOneEqQueryWrapper("out_trade_no", outTradeNo));
            if (order != null) {
                if (order.getState() == 1) {
                    //充值
                    if (order.getType() == 4) {
                        order.setState(3);
                        order.setTransactionId(transactionId);
                        orderMapper.updateById(order);
                        Wallet wallet = walletMapper.selectOne(WrapperUtils.getOneEqQueryWrapper("user_id", order.getUserId()));
                        wallet.setBalance(StringUtils.sum(order.getPrice() , wallet.getBalance()));
                        walletMapper.updateById(wallet);
                        financeMapper.insert(new Finance("余额充值", 1, 1, order.getPrice(), order.getUserId()));
                    } else {
                        if (order.getState() == 1) {
                            Wallet wallet = walletMapper.selectOne(WrapperUtils.getOneEqQueryWrapper("user_id",order.getUserId()));
                            wallet.setTicket(wallet.getTicket() + order.getTicketSum());
                            walletMapper.updateById(wallet);
                        }
                        order.setState(2);
                        order.setTransactionId(transactionId);
                        orderMapper.updateById(order);
                        financeMapper.insert(new Finance("订单支付", 4, 2, order.getPrice(), order.getUserId()));
                        //入场券流水
                        if (order.getType() == 1) {
                            financeMapper.insert(new Finance("购买入场券", 3, 1, order.getTicketSum() * 1.0, order.getUserId()));
                        }
                    }
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过余额支付
     */
    @Override
    @Transactional
    public ResponseData<Orders> payByBalance(Orders order, User user) {
        order = orderMapper.selectById(order.getId());
        if (!order.getUserId().equals(user.getId())) {
            return new ResponseData<>(ResponseState.WITHOUT_PERMISSION.getMessage(), ResponseState.WITHOUT_PERMISSION.getValue());
        }
        if (order.getState() != 1) {
            return new ResponseData<>(ResponseState.OPERATION_HAI_FINISH.getMessage(), ResponseState.OPERATION_HAI_FINISH.getValue());
        }
        if (order.getType() == 4) {
            return new ResponseData<>(ResponseState.ORDER_TYPE_ERROR.getMessage(), ResponseState.ORDER_TYPE_ERROR.getValue());
        }
        Wallet wallet = walletMapper.selectOne(WrapperUtils.getOneEqQueryWrapper("user_id", user.getId()));
        if (order.getPrice() > wallet.getBalance()) {
            return new ResponseData<>(ResponseState.BALANCE_NOT_ENOUGH.getMessage(), ResponseState.BALANCE_NOT_ENOUGH.getValue());
        }
        wallet.setBalance(StringUtils.sub(wallet.getBalance() , order.getPrice()));
        wallet.setIntegration(StringUtils.sum(wallet.getIntegration(),order.getPrice()));
        if (order.getType() == 1) {
            wallet.setTicket(wallet.getTicket() + order.getTicketSum());
        }
        walletMapper.updateById(wallet);
        order.setState(2);
        orderMapper.updateById(order);
        financeMapper.insert(new Finance("预订",2,1,order.getPrice(),user.getId()));
        financeMapper.insert(new Finance("余额支付", 1, 2, order.getPrice(), order.getUserId()));
        //入场券流水
        if (order.getType() == 1) {
            financeMapper.insert(new Finance("购买入场券", 3, 1, order.getTicketSum() * 1.0, order.getUserId()));
        }
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue(), order);
    }

    /**
     * 通过微信支付
     */
    @Override
    public ResponseData<Object> payByWx(Orders order, User user) {
        order = orderMapper.selectById(order.getId());
        if (!order.getUserId().equals(user.getId())) {
            return new ResponseData<>(ResponseState.WITHOUT_PERMISSION.getMessage(), ResponseState.WITHOUT_PERMISSION.getValue());
        }
        if (order.getState() != 1) {
            return new ResponseData<>(ResponseState.OPERATION_HAI_FINISH.getMessage(), ResponseState.OPERATION_HAI_FINISH.getValue());
        }
        if (order.getType() == 4) {
            return new ResponseData<>(ResponseState.ORDER_TYPE_ERROR.getMessage(), ResponseState.ORDER_TYPE_ERROR.getValue());
        }
        long timestamp = System.currentTimeMillis();
        String number = String.valueOf(timestamp) + user.getId();
        order.setOutTradeNo(number);
        orderMapper.updateById(order);
        user = userMapper.selectById(user.getId());
        Map<String, Object> data = wxService.JSAPIPay("orderPay", order.getOutTradeNo(), (int) (order.getPrice() * 100), user.getOpenId());
        if (data == null) {
            return new ResponseData<>(ResponseState.ERROR.getMessage(), ResponseState.ERROR.getValue());
        }
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue(), data);

    }

    /**
     * 查询个人订单
     */
    @Override
    public ResponseData<List<Orders>> getOrders(Orders order, User user) {
        order.setUserId(user.getId());
        QueryWrapper<Orders> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", user.getId());
        if (order.getType() != null && order.getType() != 0) {
            queryWrapper.eq("type", order.getType());
        }else {
            queryWrapper.in("type",1,2,3);
        }
        if (order.getState() != null && order.getState() != 0) {
            queryWrapper.eq("state", order.getState());
        }
        if (order.getDate() != null) {
            queryWrapper.eq("date", order.getDate());
        }

        queryWrapper.orderByDesc("create_at");
        List<Orders> orderList = orderMapper.selectList(queryWrapper);
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue(), orderList);
    }

    /**
     * 取消订单
     */
    @Override
    @Transactional
    public ResponseData<Orders> cancelOrder(Integer orderId, User user) throws ParseException {
        Orders order = orderMapper.selectById(orderId);
        if (order == null) {
            return new ResponseData<>(ResponseState.ORDER_NOT_EXIST.getMessage(), ResponseState.ORDER_NOT_EXIST.getValue());
        }
        //是否为该用户的订单
        if (!order.getUserId().equals(user.getId())) {
            return new ResponseData<>(ResponseState.WITHOUT_PERMISSION.getMessage(), ResponseState.WITHOUT_PERMISSION.getValue());
        }
        //是否为包场订单
        if (order.getType() != 2 && order.getType() != 3) {
            return new ResponseData<>(ResponseState.ORDER_TYPE_ERROR.getMessage(), ResponseState.ORDER_TYPE_ERROR.getValue());
        }
        //订单是否未完成
        if (order.getState() != 1 && order.getState() != 2) {
            return new ResponseData<>(ResponseState.OPERATION_HAI_FINISH.getMessage(), ResponseState.OPERATION_HAI_FINISH.getValue());
        }
        if (order.getState() == 1) {
            changeCalendarWhenCancelOrder(order);
            order.setState(4);
            orderMapper.updateById(order);
        } else if (order.getState() == 2) {
            int minTimeId=getMinTimeId(order);
            if(DateUtils.getAfterHalfDayTime().after(DateUtils.getTimeIdTime(order.getDate(),minTimeId))){
                return new ResponseData<>(ResponseState.ORDER_CAN_NOT_CANCEL.getMessage(), ResponseState.ORDER_CAN_NOT_CANCEL.getValue());

            }
            //退回余额
            Wallet wallet = walletMapper.selectOne(WrapperUtils.getOneEqQueryWrapper("user_id",order.getUserId()));
            wallet.setBalance(StringUtils.sum(order.getPrice() , wallet.getBalance()));
            walletMapper.updateById(wallet);
            order.setState(4);
            //流水记录
            financeMapper.insert(new Finance("取消订单退款", 1, 1, order.getPrice(), order.getUserId()));
//            wxService.refund(order.getTransactionId(),order.getOutRefundNo(),order.getOutTradeNo(),"cancelOrder",(int)(order.getPrice()*100),(int)(order.getPrice()*100));
            //取消日程占用
            changeCalendarWhenCancelOrder(order);
            orderMapper.updateById(order);
        }
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue());
    }

    /**
     * 退款回调
     */
    @Override
    public void refundResult(Map<String, Object> param) {
        Map<String, Object> resource = (Map<String, Object>) param.get("resource");
        try {
            Map<String, Object> result = wxService.decrypt(((String) resource.get("associated_data")).getBytes("UTF-8"), ((String) resource.get("nonce")).getBytes("UTF-8"), (String) resource.get("ciphertext"));
            String outTradeNo = (String) result.get("out_trade_no");
            String refundId = (String) result.get("refund_id");
            Orders order = orderMapper.selectOne(WrapperUtils.getOneEqQueryWrapper("out_trade_no", outTradeNo));
            if (order != null) {
                if (order.getState() != 4) {
                    order.setState(4);
                    order.setRefundId(refundId);
                    orderMapper.updateById(order);
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 未支付超时取消订单
     */
    @Override
    public void cancelOrder(Integer orderId) {
        Orders order = orderMapper.selectById(orderId);
        if (order == null) {
            return;
        }
        changeCalendarWhenCancelOrder(order);
        order.setState(4);
        orderMapper.updateById(order);
    }

    /**
     * 管理员查询订单
     */
    @Override
    public ResponseData<IPage<Orders>> adminGetOrders(Orders order) {
        QueryWrapper<Orders> queryWrapper = new QueryWrapper<>();
        User user = null;
        if (order.getUserId() != null) {
            queryWrapper.eq("user_id", order.getUserId());
        }
        if (order.getUser() != null) {
            if (order.getUser().getPhone() != null) {
                user = userMapper.selectOne(WrapperUtils.getOneEqQueryWrapper("phone", order.getUser().getPhone()));
                if (user != null) {
                    //如果同时传入userId和phone看是否为同一用户
                    if (order.getUserId() != null) {
                        if (!user.getId().equals(order.getUserId())) {
                            return new ResponseData<>("userId和phone不一致", ResponseState.PARAM_IS_ERROR.getValue());
                        }
                    } else {
                        queryWrapper.eq("user_id", user.getId());
                    }
                } else {
                    return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue(), null);
                }
            }
        }
        if (order.getType() != null && order.getType() != 0) {
            queryWrapper.eq("type", order.getType());
        }else {
            queryWrapper.in("type",1,2,3);
        }
        if (order.getState() != null && order.getState() != 0) {
            queryWrapper.eq("state", order.getState());
        }
        if (order.getDate() != null) {
            queryWrapper.eq("date", order.getDate());
        }
        queryWrapper.orderByDesc("create_at");
        Page<Orders> ordersPage = new Page<>();
        if (order.getCurrent() != null && order.getSize() != null) {
            ordersPage = new Page<>(order.getCurrent(), order.getSize());
        }
        IPage<Orders> ordersIPage = orderMapper.selectPage(ordersPage, queryWrapper);
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue(), ordersIPage);
    }

    /**
     * 管理员完成订单
     */
    @Override
    public ResponseData<Orders> adminFinishOrder(Orders order)        {
        order=orderMapper.selectById(order.getId());
        if (order == null) {
            return new ResponseData<>(ResponseState.ORDER_NOT_EXIST.getMessage(), ResponseState.ORDER_NOT_EXIST.getValue());
        }
        //是否为包场订单
        if (order.getType() != 2 && order.getType() != 3) {
            return new ResponseData<>(ResponseState.ORDER_TYPE_ERROR.getMessage(), ResponseState.ORDER_TYPE_ERROR.getValue());
        }
        //订单是否未完成
        if (order.getState() != 2) {
            return new ResponseData<>(ResponseState.OPERATION_HAI_FINISH.getMessage(), ResponseState.OPERATION_HAI_FINISH.getValue());
        }
        order.setState(3);
        orderMapper.updateById(order);
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue(), order);
    }

    /**
     * 获取最小的timeId
     */
    private Integer getMinTimeId(Orders order) {
        JSONArray jsonArray = JSONArray.parseArray(order.getCalendarId());
        Object[] calendarIdArray = jsonArray.toArray();
        Arrays.sort(calendarIdArray);
        return (Integer) calendarIdArray[0];
    }

    /**
     * 取消订单时将日程设为空闲
     */
    private void changeCalendarWhenCancelOrder(Orders order) {
        JSONArray jsonArray = JSONArray.parseArray(order.getCalendarId());
        Object[] calendarIdArray = jsonArray.toArray();
        if (order.getType() == 2) {
            for (Object calendarId : calendarIdArray) {
                changeCalendarState(order.getDate(), (int) calendarId, order.getCourtId(), (short) 1);
            }
        } else if (order.getType() == 3) {
            if (order.getCourtId() == 5) {
                for (Object calendarId : calendarIdArray) {
                    changeCalendarState(order.getDate(), (int) calendarId, 1, (short) 1);
                    changeCalendarState(order.getDate(), (int) calendarId, 2, (short) 1);
                }
            } else if (order.getCourtId() == 6) {
                for (Object calendarId : calendarIdArray) {
                    changeCalendarState(order.getDate(), (int) calendarId, 3, (short) 1);
                    changeCalendarState(order.getDate(), (int) calendarId, 4, (short) 1);
                }
            }
        }
    }

    /**
     * 根据日程日期，时间，场地修改日程状态
     */
    private void changeCalendarState(Date date, Integer timeId, Integer courtId, Short state) {
        UpdateWrapper<Calendar> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("date", date);
        updateWrapper.eq("time_id", timeId);
        updateWrapper.eq("court_id", courtId);
        updateWrapper.set("user_id",null);
        calendarMapper.update(new Calendar(timeId, date, courtId, state,null), updateWrapper);
    }
}
